package com.ruoyi.blockchain;

import java.security.*;
import java.util.Base64;

/**
 * 交易类 - 表示区块链中的一笔交易
 * 包含交易的发送方、接收方、金额和签名等信息
 */
public class Transaction {
    private String transactionId;  // 交易ID（哈希值）
    private PublicKey sender;      // 发送方公钥
    private PublicKey recipient;   // 接收方公钥
    private double value;          // 交易金额
    private byte[] signature;      // 交易签名，用于验证交易的真实性

    /**
     * 构造函数
     * @param sender 发送方公钥
     * @param recipient 接收方公钥
     * @param value 交易金额
     */
    public Transaction(PublicKey sender, PublicKey recipient, double value) {
        this.sender = sender;
        this.recipient = recipient;
        this.value = value;
        this.transactionId = calculateHash();
    }

    /**
     * 计算交易的哈希值
     * @return 交易的哈希值
     */
    public String calculateHash() {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            
            String dataToHash = getStringFromKey(sender) + getStringFromKey(recipient) + Double.toString(value);
            byte[] hashBytes = digest.digest(dataToHash.getBytes());
            
            StringBuilder hashStringBuilder = new StringBuilder();
            for (byte b : hashBytes) {
                hashStringBuilder.append(String.format("%02x", b));
            }
            
            return hashStringBuilder.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("SHA-256算法不可用", e);
        }
    }

    /**
     * 生成交易签名
     * @param privateKey 发送方私钥
     */
    public void generateSignature(PrivateKey privateKey) {
        try {
            // 使用Java内置的SHA256withRSA算法
            Signature signatureInstance = Signature.getInstance("SHA256withRSA");
            signatureInstance.initSign(privateKey);
            
            String data = getStringFromKey(sender) + getStringFromKey(recipient) + Double.toString(value);
            signatureInstance.update(data.getBytes());
            
            this.signature = signatureInstance.sign();
        } catch (Exception e) {
            throw new RuntimeException("生成交易签名失败", e);
        }
    }

    /**
     * 验证交易签名是否有效
     * @return 如果签名有效返回true，否则返回false
     */
    public boolean verifySignature() {
        try {
            // 如果是创世区块的交易（没有发送方），则视为有效
            if (sender == null) return true;
            
            // 如果没有签名，视为无效
            if (signature == null || signature.length == 0) {
                System.out.println("交易没有签名");
                return false;
            }
            
            // 使用Java内置的SHA256withRSA算法
            Signature signatureInstance = Signature.getInstance("SHA256withRSA");
            signatureInstance.initVerify(sender);
            
            String data = getStringFromKey(sender) + getStringFromKey(recipient) + Double.toString(value);
            signatureInstance.update(data.getBytes());
            
            return signatureInstance.verify(signature);
        } catch (Exception e) {
            throw new RuntimeException("验证交易签名失败", e);
        }
    }

    /**
     * 检查交易是否有效
     * @return 如果交易有效返回true，否则返回false
     */
    public boolean isValid() {
        // 创世区块交易视为有效
        if (sender == null) return true;
        
        // 检查是否有签名
        if (signature == null || signature.length == 0) {
            System.out.println("交易没有签名");
            return false;
        }
        
        // 验证签名
        if (!verifySignature()) {
            System.out.println("交易签名无效");
            return false;
        }
        
        // 检查交易ID是否与计算的哈希匹配
        if (!transactionId.equals(calculateHash())) {
            System.out.println("交易ID与哈希不匹配");
            return false;
        }
        
        return true;
    }

    /**
     * 将公钥转换为字符串
     * @param key 公钥
     * @return 公钥的字符串表示，如果key为null则返回"null"
     */
    public static String getStringFromKey(Key key) {
        if (key == null) {
            return "null";
        }
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    /**
     * 从字符串还原公钥
     * @param keyString 公钥的字符串表示
     * @return 公钥对象
     * @throws Exception 解析异常
     */
    public static PublicKey getKeyFromString(String keyString) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(keyString);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(new java.security.spec.X509EncodedKeySpec(keyBytes));
    }

    /**
     * 生成密钥对
     * @return 密钥对（包含公钥和私钥）
     * @throws Exception 生成异常
     */
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        return keyGen.generateKeyPair();
    }

    // Getters
    public String getTransactionId() { return transactionId; }
    public PublicKey getSender() { return sender; }
    public PublicKey getRecipient() { return recipient; }
    public double getValue() { return value; }
    public byte[] getSignature() { return signature; }

    @Override
    public String toString() {
        return "Transaction{" +
                "transactionId='" + transactionId + '\'' +
                ", sender='" + (sender != null ? getStringFromKey(sender) : "null") + '\'' +
                ", recipient='" + (recipient != null ? getStringFromKey(recipient) : "null") + '\'' +
                ", value=" + value +
                ", signatureValid=" + verifySignature() +
                '}';
    }
}